﻿using System;
using System.IO;
using System.Linq;
using System.Threading;
using Lucene.Linq.VSTests.Helpers;
using Lucene.Net.Store;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Lucene.Linq.Search;

namespace Lucene.Linq.VSTests
{
    [TestClass]
    public class TestIndex
    {
        private readonly Action<Index<Sample>>
            simpleTest = (idx) =>
                             {
                                 Sample first = SampleGenerator.GetRandom(1).First();
                                 Sample second = SampleGenerator.GetRandom(1).First();
                                 Sample third = SampleGenerator.GetRandom(1).First();

                                 idx.Add(first);
                                 idx.Add(second);
                                 idx.Add(third);
                                 Console.WriteLine("index count: {0}", idx.Count);
                                 Assert.IsTrue(idx.Count == 3);

                                 idx.Delete(0);
                                 idx.Delete(1);
                                 Assert.IsTrue(idx.Count == 1);
                             };

        #region ctors

        [TestMethod, ExpectedException(typeof(ArgumentNullException))]
        public void Construct_Throws_null_on_directory_or_path()
        {
            var i1 = new Index<Sample>((string)null);

            var i2 = new Index<Sample>((DirectoryInfo)null);
        }

        [TestMethod]
        public void Construct_Creates_Ram_directory()
        {
            using (var i = new Index<Sample>())
            {
                simpleTest(i);
                Assert.IsTrue(i.Directory is RAMDirectory);
            }
        }

        [TestMethod]
        public void Construct_With_Path_Or_DirectoryInfo_Creates_Fs_Directory()
        {
            var r = new Random();

            string path = Environment.CurrentDirectory;
            var indexDir = new DirectoryInfo(Path.Combine(path, "ctor_dir" + r.String(10)));

            using (var i = new Index<Sample>(Path.Combine(path, "ctor_path" + r.String(10))))
            {
                simpleTest(i);
                Assert.IsTrue(i.Directory is FSDirectory);
            }

            using (var i = new Index<Sample>(indexDir))
            {
                simpleTest(i);
                Assert.IsTrue(i.Directory is FSDirectory);
            }
        }

        #endregion

        [TestMethod]
        public void Index_implements_IQueryable()
        {
            Type ts = typeof(Index<Sample>);
            Type iqueryable = typeof(IQueryable);
            Type iqueryablet = typeof(IQueryable<Sample>);

            Assert.IsTrue(iqueryable.IsAssignableFrom(ts));
            Assert.IsTrue(iqueryablet.IsAssignableFrom(ts));
        }

        [TestMethod]
        public void Adding_items_should_add_document()
        {
            using (var i = new Index<Sample>())
            {
                Assert.IsTrue(i.Count == 0);
                i.Add(SampleGenerator.GetRandom(10).Take(3));
                Console.WriteLine(i.Count);
                Assert.IsTrue(i.Count == 3);
            }
        }

        [TestMethod]
        public void Deleting_items_should_remove_them_from_index()
        {
            var deleteAndCheckNotIndexed =
                new Action<Index<Sample>, Sample>((idx, s) =>
                                                      {
                                                          idx.Delete(s.MrString);
                                                          idx.Add(SampleGenerator.GetRandom(1));
                                                          Console.WriteLine((from b in idx
                                                                             where
                                                                                 (b.MrString ==
                                                                                  s.MrString)
                                                                             select b).Count());

                                                          Assert.IsFalse(
                                                              (from b in idx
                                                               where
                                                                   (b.MrString == s.MrString)
                                                               select b).Count() != 0
                                                              ,
                                                              s.MrString +
                                                              " was erroneously found in the index");
                                                      });

            string path = Path.Combine(Environment.CurrentDirectory, (new Random().String(12)));

            using (var i = new Index<Sample>(path))
            {
                Assert.IsTrue(i.Count == 0);

                Sample first = SampleGenerator.GetRandom(1).First();
                Sample second = SampleGenerator.GetRandom(1).First();
                Sample third = SampleGenerator.GetRandom(1).First();
                Sample fourth = SampleGenerator.GetRandom(1).First();
                Sample fifth = SampleGenerator.GetRandom(1).First();
                Sample six = SampleGenerator.GetRandom(1).First();

                i.Add(first);
                i.Add(second);
                i.Add(third);
                i.Add(fourth);
                i.Add(fifth);
                i.Add(six);

                Console.WriteLine("index count: {0}", i.Count);
                Assert.IsTrue(i.Count == 6);

                // need to cast to IIndex to delete using docIds- that's ok in my opinion
                var iindex = i as IIndex;

                // delete first,second
                iindex.Delete(0);
                iindex.Delete(1);


                Assert.IsTrue(i.Count == 4);

                // check the first,second are not in index
                IQueryable<Sample> firstOrSecondSearch =
                    from b in i
                    where
                        (b.MrString == second.MrString)
                        ||
                        (b.MrString == first.MrString)
                    select b;

                Assert.AreEqual(firstOrSecondSearch.Count(), 0);

                // delete third,fourth
                deleteAndCheckNotIndexed(i, fifth);
                deleteAndCheckNotIndexed(i, six);
            }
        }

        [TestMethod]
        public void Disposing_Index_nullifies_directory_and_Context()
        {
            Index<Sample> i = null;
            using (i = new Index<Sample>())
            {
                Thread.Sleep(100);
            }
            Assert.IsNull(i.Directory);
            Assert.IsNull(i.Context);
        }
    }
}